
var CI = Components.interfaces, CC = Components.classes, CR = Components.results;
var MY_ID = "url_rewriter@gmail.com";
const kbIsDebug = true;
const ksConfigFileName = "ur.xml";

var UrlBarListener = {
 QueryInterface: function(aIID)
 {
   if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
       aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
       aIID.equals(Components.interfaces.nsISupports))
     return this;
   throw Components.results.NS_NOINTERFACE;
 },

 onLocationChange: function(aProgress, aRequest, aURI)
 {
 },

 onStateChange: function(aWebProgress,
			 aRequest,
			 aStateFlags,
			 aStatus)
 {
   if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START)
   {
     URLRewriter.processNewURL(aRequest.URI);
   }
 },

 onProgressChange: function(a, b, c, d, e, f) {},
 onStatusChange: function(a, b, c, d) {},
 onSecurityChange: function(a, b, c) {}
};


function logMessageToConsole(sMsg)
{
  try {
    // It would appear that the console service is threadsafe.
    var oConsole = Components.classes["@mozilla.org/consoleservice;1"]
      .getService(Components.interfaces.nsIConsoleService);
    oConsole.logStringMessage(sMsg);
  } catch (e) {
    alert("Error:" + e);
  }
}


var URLRewriter = {
 sOldURL: null,
 rwInfoContainer: null,

 init: function() {
    // Listen for webpage loads
    gBrowser.addProgressListener(UrlBarListener,
				 Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
    URLRewriteConfReader.init(ksConfigFileName);
    this.rwInfoContainer = URLRewriteConfReader.getRwInfoContainer();
  },

 uninit: function() {
    gBrowser.removeProgressListener(UrlBarListener);
  },

 transform: function(objURI)
 {
   //objURI.spec = "http://google.com";
   //Information about URI object
   //scheme = http or file
   //path = path
   //host = hostname
   sURIInfo = "PrePath : " + objURI.prePath + ", "
   sURIInfo += "Scheme :" + objURI.scheme + ", ";
   sURIInfo += "Path :" + objURI.path + ",";
   sURIInfo += "Host :" + objURI.host + ",";
   sURIInfo += "Port :" + objURI.port + ",";
   logMessageToConsole(sURIInfo);
 },
  
 processNewURL: function(aURI) {
    if (aURI.spec == this.sOldURL)
      return;
    bMatched = false;
    for (iIndex = 0 ; iIndex < this.rwInfoContainer.getTotal(); iIndex++)
    {
      vInputRegExpr = this.rwInfoContainer.getRwContent(iIndex).getInput();
      sCurrentURL  = aURI.spec;
      for (iRegExprId = 0; iRegExprId < vInputRegExpr.length; iRegExprId++)
      {
	if (sCurrentURL.match(vInputRegExpr[iRegExprId]))
	{
	  this.convertURL(aURI, this.rwInfoContainer.getRwContent(iIndex));
	  bMatched = true;
	  break;
	}
	else
	{	
	  //alert("Not Matched : URL " + sCurrentURL + " RegExp " + vInputRegExpr[iRegExprId]);
	}
      }
      if (bMatched)
	break;
    }
    this.sOldURL = aURI.spec; 
    if (bMatched)
    {
      //sOldURL is actually a rewritten new URL.
      window.content.location = this.sOldURL;
    }
  },

 convertURL: function(oURISpec, oRwInfo) {
    oRwOutput = oRwInfo.m_oRwOutput;
    oURISpec.host = (oRwOutput.isHostAsPrev() ==  false) ?
                     oRwOutput.m_sHost : oURISpec.host;

    oURISpec.port = (oRwOutput.isPortAsPrev() ==  false) ?
                     oRwOutput.m_iPort : oURISpec.port;

    oURISpec.path = (oRwOutput.isPathAsPrev() ==  false) ?
                      oRwOutput.m_sPath : oURISpec.path;
  },

 testRegExp: function() {
   var sInputRegExpr = "http://review/\w?";
   var sInputStr = "http://review/";
   if (sInputStr.match(sInputRegExpr))
   {
     alert("Matched");
   }
   else
   {
     alert("Not matched");
   }
 },
};

function RWOutput(sHost, iPort, sPath,
		  bPrevHost, bPrevPort,
		  bPrevPath)
{
  this.m_sHost = sHost;
  this.m_iPort = iPort;
  this.m_sPath = sPath;
  this.m_bPrevHost = bPrevHost;
  this.m_bPrevPort = bPrevPort;
  this.m_bPrevPath = bPrevPath;
}

RWOutput.prototype.toString = function()  {
  sStrRep = "Host : " + this.m_sHost + ((this.m_bPrevHost == true) ? "(Prev)":"");
  sStrRep += "Port : " + this.m_iPort + ((this.m_bPrevPort == true) ? "(Prev)":"");
  sStrRep += "Path : " + this.m_sPath + ((this.m_bPrevPath == true) ? "(Prev)":"");
  return sStrRep;
};



RWOutput.prototype.isHostAsPrev = function()  {
  return this.m_bPrevHost;
};

RWOutput.prototype.isPortAsPrev = function()  {
  return this.m_bPrevPort;
};

RWOutput.prototype.isPathAsPrev = function()  {
    return this.m_bPrevPath;
};
  
function URLRewriteInfo(vInput, oRwOutput)
{
  this.m_vInput = vInput;
  this.m_oRwOutput = oRwOutput; 
}

URLRewriteInfo.prototype.toString = function() {
  sStrRep = "Input : " + this.m_sInput;
  sStrRep += ",Output : " + this.m_oRwOutput.toString();
  return sStrRep;
};

URLRewriteInfo.prototype.getInput = function() {
  return this.m_vInput;
}

function RwInfoContainer()
{
  //Rewrite Info object container.
  this.vRInfo = [];
}

RwInfoContainer.prototype.getTotal = function() {
  return this.vRInfo.length;
};

RwInfoContainer.prototype.pushInfo = function(sInfo) {
  this.vRInfo.push(sInfo);
};

RwInfoContainer.prototype.getRwContent = function(iIndex) {
  return this.vRInfo[iIndex];
};


var URLRewriteConfReader =
{
 rwInfoContainer: null,

 getConfFile: function() {
    var em = Components.classes["@mozilla.org/extensions/manager;1"].
    getService(Components.interfaces.nsIExtensionManager);
    var oConfFile = em.getInstallLocation(MY_ID).getItemFile(MY_ID,
							     ksConfigFileName);
    return oConfFile;
  },

 getRwInfoContainer: function()  {
    return this.rwInfoContainer;
  },
  
  loadSettings : function()  {
    oConfFile = this.getConfFile(); 
    logMessageToConsole("Path : " + oConfFile.path);
    
    var s = CC["@mozilla.org/network/file-input-stream;1"].createInstance(CI.nsIFileInputStream);
    s.init(oConfFile, -1, -1, CI.nsIFileInputStream.CLOSE_ON_EOF);
    var p = CC["@mozilla.org/xmlextras/domparser;1"].createInstance(CI.nsIDOMParser);
    var doc = p.parseFromStream(s, null, oConfFile.fileSize, "text/xml");
    if (!doc || doc.documentElement.nodeName == "parsererror") {
      alert("Error : " +  oConfFile.path +
	    " does not contain valid XML configuration");
      return;
    }
    this.rwInfoContainer = new RwInfoContainer();

    var arrElements = doc.getElementsByTagName("url_rewrite_entry");
    for (var iElemId = 0; iElemId < arrElements.length; iElemId++)
    {
      var eEntryElem = arrElements[iElemId];
      eInputElement = eEntryElem.getElementsByTagName("input")[0];

      arrRegExprElem = eInputElement.getElementsByTagName("regexpr");
      var vRegExpr = [];
      for (var iRegExprId = 0; iRegExprId < arrRegExprElem.length; iRegExprId++)
      {
	eRegExprElem = arrRegExprElem[iRegExprId]; 
	sInput = eRegExprElem.firstChild.data;
	vRegExpr.push(sInput);
	logMessageToConsole("Input : " + sInput);
      }

      eOutputElement = eEntryElem.getElementsByTagName("output")[0];
      eSchemeElem = eOutputElement.getElementsByTagName("scheme")[0];
      bSchemeAsPrev = eSchemeElem.hasAttribute("mode") ?
	eSchemeElem.getAttribute("mode") == "asPrev" : false;
      logMessageToConsole("SchemeAsPrev : " + bSchemeAsPrev);
      sOutputScheme = eSchemeElem.QueryInterface(Ci.nsIDOM3Node).textContent;
      logMessageToConsole("Output scheme : " + sOutputScheme);
      
      eHostElem = eOutputElement.getElementsByTagName("host")[0];
      bHostAsPrev = eHostElem.hasAttribute("mode") ?
	eHostElem.getAttribute("mode") == "asPrev" : false;
      logMessageToConsole("HostAsPrev : " + bHostAsPrev);
      sOutputHost = eHostElem.QueryInterface(Ci.nsIDOM3Node).textContent;
      logMessageToConsole("Output host : " + sOutputHost);
 
      
      ePortElem = eOutputElement.getElementsByTagName("port")[0];
      bPortAsPrev = ePortElem.hasAttribute("mode") ?
	ePortElem.getAttribute("mode") == "asPrev" : false;
      logMessageToConsole("PortAsPrev : " + bPortAsPrev);
      sOutputPort = ePortElem.QueryInterface(Ci.nsIDOM3Node).textContent;
      logMessageToConsole("Output port : " + sOutputPort);
 
      
      ePathElem = eOutputElement.getElementsByTagName("path")[0];
      bPathAsPrev = ePathElem.hasAttribute("mode") ?
	ePathElem.getAttribute("mode") == "asPrev" : false;
      logMessageToConsole("PathAsPrev : " + bPathAsPrev);
      sOutputPath = ePathElem.QueryInterface(Ci.nsIDOM3Node).textContent;
      logMessageToConsole("Output path : " + sOutputPath);
 
      
      rwOutput = new RWOutput(sOutputHost, sOutputPort, sOutputPath,
			      bHostAsPrev, bPortAsPrev, bPathAsPrev);

      urlRwInfo = new URLRewriteInfo(vRegExpr, rwOutput);
      this.rwInfoContainer.pushInfo(urlRwInfo);
    }
    return true;
  },
 
  
 init: function(sFileName) {
    
    this.sFileName = sFileName;
    try
    {
      this.loadSettings();
    }
    catch(oError)
    {
      alert(oError);
    }
  },
 
};


window.addEventListener("load", function() {URLRewriter.init()}, false);
window.addEventListener("unload", function() {URLRewriter.uninit()}, false);
